// Tencent is pleased to support the open source community by making
// 蓝鲸智云 - 监控平台/日志平台 (BlueKing - Monitor/Log) available.
// Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved.
// Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://opensource.org/licenses/MIT
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//

package confengine

import (
	"fmt"

	"github.com/TencentBlueKing/bkmonitor-kits/logger"
	"github.com/TencentBlueKing/collector-go-sdk/v2/bkbeat/beat"

	"github.com/TencentBlueKing/bk-collector/define"
)

// Config 是对 beat.Config 的封装 并提供一些简便的操作函数
type Config struct {
	conf *beat.Config
}

func New(conf *beat.Config) *Config {
	return &Config{conf: conf}
}

func (c *Config) Has(s string) bool {
	ok, err := c.conf.Has(s, -1)
	if err != nil {
		return false
	}
	return ok
}

func (c *Config) Child(s string) (*Config, error) {
	content, err := c.conf.Child(s, -1)
	if err != nil {
		return nil, err
	}
	return &Config{conf: content}, nil
}

func (c *Config) Unpack(to interface{}) error {
	return c.conf.Unpack(to)
}

func (c *Config) UnpackChild(s string, to interface{}) error {
	content, err := c.conf.Child(s, -1)
	if err != nil {
		return err
	}
	return content.Unpack(to)
}

func (c *Config) UnpackIntWithDefault(s string, val int) int {
	n, err := c.conf.Int(s, -1)
	if err != nil {
		return val
	}
	return int(n)
}

const (
	KeyGlobal = "__global__"
)

// TierConfig 实现了层级 Config 管理和查找的能力
// 配置总共有四个搜索路径，搜索顺序为 1) -> 2) -> 3) -> 4)
//
// 4) global.config			全局主配置（KeyGlobal）
// 3) subconfigs.default	子配置默认配置（SubConfigFieldDefault）
// 2) subconfigs.service	子配置服务级别配置（SubConfigFieldService）
// 1) subconfigs.instance	子配置实例级别配置（SubConfigFieldInstance）
//
// 一个子配置文件描述了某个唯一标识的应用的自定义配置
type TierConfig struct {
	m map[string]interface{}
}

func NewTierConfig() *TierConfig {
	return &TierConfig{m: map[string]interface{}{}}
}

func (tc *TierConfig) decodeName(token, typ, id string) string {
	return fmt.Sprintf("%s//%s//%s", token, typ, id)
}

func (tc *TierConfig) SetGlobal(val interface{}) {
	tc.m[KeyGlobal] = val
}

func (tc *TierConfig) Set(token, typ, id string, val interface{}) {
	tc.m[tc.decodeName(token, typ, id)] = val
}

func (tc *TierConfig) Keys() []string {
	var keys []string
	for k := range tc.m {
		keys = append(keys, k)
	}
	return keys
}

func (tc *TierConfig) Get(token, serviceID, instanceID string) interface{} {
	val, typ := tc.get(token, serviceID, instanceID)
	logger.Debugf("tier config(token=%s, serviceID=%s, instanceID=%s), type: %s", token, serviceID, instanceID, typ)
	return val
}

func (tc *TierConfig) get(token, serviceID, instanceID string) (interface{}, string) {
	// 1) subconfigs.instance
	if instanceID != "" {
		v, ok := tc.m[tc.decodeName(token, define.SubConfigFieldInstance, instanceID)]
		if ok {
			return v, define.SubConfigFieldInstance
		}
	}

	// 2) subconfigs.service
	if serviceID != "" {
		v, ok := tc.m[tc.decodeName(token, define.SubConfigFieldService, serviceID)]
		if ok {
			return v, define.SubConfigFieldService
		}
	}

	// 3) subconfigs.default
	v, ok := tc.m[tc.decodeName(token, define.SubConfigFieldDefault, "")]
	if ok {
		return v, define.SubConfigFieldDefault
	}

	// 4) global.config
	return tc.m[KeyGlobal], KeyGlobal
}

func (tc *TierConfig) GetByToken(token string) interface{} {
	return tc.Get(token, "", "")
}
